package com.dana1.nos.old.impl.springjdbc;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;

import javax.sql.DataSource;

import org.apache.commons.lang.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;

import com.dana1.nos.old.ObjectKey;
import com.dana1.nos.old.ServiceObject;
import com.dana1.nos.old.impl.AbstractObjectService;
import com.dana1.nos.old.impl.ServiceObjectInvocationHandler;
import com.dana1.nos.old.util.PropertyUtils;

public class SpringJDBCObjectService extends AbstractObjectService
{
	private DataSource dataSource;
	private SimpleJdbcTemplate simpleTemplate;
	// search operations
	@Override public <T extends ServiceObject> List<ObjectKey<T>> query(T obj) { return null; }

	// passthru operation. The multiple sql statements are so that a true list of affected object keys can be returned by the underlying driver
	@Override public List<ObjectKey<?>> execute(Map<String,Object> parameters, String ... sql) { return null; }

	
	// Object operations
	@Override 
	public <T extends ServiceObject> ObjectKey<T> insert(T obj) 
	{
		// TODO implement me
		return null;
	};
	@Override
	public <T extends ServiceObject> T retrieve(ObjectKey<T> key)
	{
		T obj = null;
		Map<String,Object> rawValues = simpleTemplate.queryForMap(queryForServiceObjectByKey(key),key.getKeyValues());
		obj = (T)newInstance(key.getServiceObjectClass());
		populateHandlerFromValues(handlerFor(obj),rawValues);
		handlerFor(obj).setAutoInsertServiceObjectProperties(isAutoInsertServiceObjects());
		handlerFor(obj).setConnected(true);
		return obj;
	}
	@Override
	public <T extends ServiceObject> void update(T obj) {
		// TODO implement me
	};
	@Override
	public <T extends ServiceObject> void delete(ObjectKey<T> key)
	{
		T obj = null;
		// TODO implement me
		if (obj!=null)
			handlerFor(obj).setConnected(false);
	}
	// relation operations
	@Override 
	public List<ObjectKey<?>> retrieveMM(ObjectKey<? extends ServiceObject> ownerKey,String relationName) 
	{ 
		// TODO implement me
		return null;
	}
	@Override 
	public int countMM(ObjectKey<? extends ServiceObject> ownerKey,String relationName) 
	{ 
		// TODO implement me
		return retrieveMM(ownerKey, relationName).size();
	}
	@Override 
	public boolean addMM(ObjectKey<? extends ServiceObject> ownerKey, String relationName, ObjectKey<? extends ServiceObject> childKey) 
	{
		ServiceObject obj = retrieve(childKey);
		if ((null==obj)||(!handlerFor(obj).isConnected()))
			throw new UnsupportedOperationException("The child element must be connected before insertion");

		// TODO implement me
		return false;
	}
	@Override 
	public boolean removeMM(ObjectKey<? extends ServiceObject> ownerKey, String relationName, ObjectKey<? extends ServiceObject> childKey) 
	{
		// TODO implement me
		return false;
	}
	
	// relation operations (inverse FK)
	@Override 
	public <T extends ServiceObject> List<ObjectKey<T>> retrieve1M(ObjectKey<?> childKey,Class<T> parentObjectClass,String relationName) 
	{ 
		if (Proxy.isProxyClass(parentObjectClass))
			throw new IllegalArgumentException("parentObjectClass must not be a proxy class");
		// TODO implement me
		return null;
	}
	@Override 
	public int count1M(ObjectKey<? extends ServiceObject> childKey,Class<? extends ServiceObject> parentObjectClass,String relationName) 
	{ 
		// TODO implement me
		return retrieve1M(childKey, parentObjectClass, relationName).size(); 
	}
	@Override 
	public boolean add1M(ObjectKey<? extends ServiceObject> childKey, String relationName, ObjectKey<? extends ServiceObject> parentKey) 
	{ 
		// TODO implement me
		return true; 
	}
	@Override public boolean remove1M(ObjectKey<? extends ServiceObject> childKey, String relationName, ObjectKey<? extends ServiceObject> parentKey) 
	{ 
		// TODO implement me
		return true; 
	}

	@Override public boolean set11(ObjectKey<? extends ServiceObject> ownerKey, String relationName, ObjectKey<? extends ServiceObject> childKey) 
	{ 
		// TODO implement me
		return true;
	}

	private String queryForServiceObjectByKey(ObjectKey<?> key)
	{
		Set<String> columnNamesForObject = columnNamesForServiceObject(key.getServiceObjectClass());

		StringBuilder query = new StringBuilder("");
		query.append("select ").append(StringUtils.join(columnNamesForObject, ", "));
		query.append(" from ").append(tableNameForServiceObject(key.getServiceObjectClass()));

		List<String> clauses = clausesForObjectKey(key);
		if (!clauses.isEmpty())
			query.append("where ").append(StringUtils.join(clauses," and "));
		
		return query.toString();
	}

	private Set<String> columnNamesForServiceObject(Class<?> serviceObjectClass)
	{
		return null;
		
	}

	private Object tableNameForServiceObject(Class<?> serviceObjectClass)
	{
		return null;
		
	}

	private List<String> clausesForObjectKey(ObjectKey<?> key)
	{
		List<String> clauses = new LinkedList<String>();
		for (Map.Entry<String,Comparable<?>> me: key.getKeyValues().entrySet())
			if (null!=me.getValue())
				clauses.add(me.getKey()+" = :"+me.getKey());
		return clauses;
	}

	private void populateHandlerFromValues(ServiceObjectInvocationHandler<?> handler,Map<String,Object> values)
	{
		// convert out any serviceObject property references to keys
		
	}
	
}
